package com.bi.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bi.entity.WideTable;
import com.bi.entity.WideTableField;
import com.bi.mapper.WideTableMapper;
import com.bi.service.ExcelImportService;
import com.bi.service.ElasticsearchService;
import com.bi.mapper.WideTableFieldMapper;
import com.bi.vo.ImportTaskStatus;
import com.bi.vo.ExcelValidationResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Excel导入服务实现类
 * 
 * @author BI Platform Team
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ExcelImportServiceImpl implements ExcelImportService {
    
    private final WideTableMapper wideTableMapper;
    private final WideTableFieldMapper wideTableFieldMapper;
    private final ElasticsearchService elasticsearchService;
    private final RedisTemplate<String, Object> redisTemplate;
    
    private static final String TASK_STATUS_KEY = "excel_import_task:";
    private static final int BATCH_SIZE = 1000;
    private final Map<String, ImportTaskStatus> taskStatusMap = new ConcurrentHashMap<>();
    
    @Override
    public List<String> parseExcelHeaders(MultipartFile file) {
        // TODO: 实现解析Excel文件头部信息
        return new ArrayList<>();
    }

    @Override
    public List<Map<String, Object>> previewExcelData(MultipartFile file, int maxRows) {
        // TODO: 实现预览Excel数据
        return new ArrayList<>();
    }

    @Override
    public String importExcelData(MultipartFile file, Long wideTableId, String importMode, 
                                 Map<String, String> fieldMapping) {
        return startImport(wideTableId, file);
    }

    @Override
    public ImportTaskStatus getImportTaskStatus(String taskId) {
        return getTaskStatus(taskId);
    }

    @Override
    public boolean cancelImportTask(String taskId) {
        try {
            cancelTask(taskId);
            return true;
        } catch (Exception e) {
            log.error("取消导入任务失败: taskId={}, error={}", taskId, e.getMessage());
            return false;
        }
    }

    @Override
    public ExcelValidationResult validateExcelFile(MultipartFile file, Long wideTableId) {
        // TODO: 实现验证Excel文件格式
        return new ExcelValidationResult();
    }

    public String startImport(Long wideTableId, MultipartFile file) {
        // 生成任务ID
        String taskId = "import_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
        
        // 初始化任务状态
        ImportTaskStatus taskStatus = new ImportTaskStatus();
        taskStatus.setTaskId(taskId);
        taskStatus.setStatus(ImportTaskStatus.TaskStatus.PENDING);
        taskStatus.setProgress(0);
        taskStatus.setStartTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        taskStatus.setErrorDetails(new ArrayList<>());
        
        // 保存任务状态到内存和Redis
        taskStatusMap.put(taskId, taskStatus);
        redisTemplate.opsForValue().set(TASK_STATUS_KEY + taskId, taskStatus, 24, TimeUnit.HOURS);
        
        // 异步执行导入任务
        processImportAsync(taskId, wideTableId, file);
        
        return taskId;
    }
    
    public ImportTaskStatus getTaskStatus(String taskId) {
        // 先从内存获取
        ImportTaskStatus status = taskStatusMap.get(taskId);
        if (status != null) {
            return status;
        }
        
        // 从Redis获取
        Object redisStatus = redisTemplate.opsForValue().get(TASK_STATUS_KEY + taskId);
        if (redisStatus instanceof ImportTaskStatus) {
            return (ImportTaskStatus) redisStatus;
        }
        
        return null;
    }
    
    public void cancelTask(String taskId) {
        ImportTaskStatus taskStatus = getTaskStatus(taskId);
        if (taskStatus != null && taskStatus.getStatus() == ImportTaskStatus.TaskStatus.RUNNING) {
            taskStatus.setStatus(ImportTaskStatus.TaskStatus.CANCELLED);
            taskStatus.setEndTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            updateTaskStatus(taskId, taskStatus);
        }
    }
    
    @Async
    public void processImportAsync(String taskId, Long wideTableId, MultipartFile file) {
        ImportTaskStatus taskStatus = getTaskStatus(taskId);
        if (taskStatus == null) {
            return;
        }
        
        try {
            // 更新状态为运行中
            taskStatus.setStatus(ImportTaskStatus.TaskStatus.RUNNING);
            updateTaskStatus(taskId, taskStatus);
            
            // 获取宽表信息
            WideTable wideTable = wideTableMapper.selectById(wideTableId);
            if (wideTable == null) {
                throw new RuntimeException("宽表不存在: " + wideTableId);
            }
            
            // 获取字段信息
            List<WideTableField> fields = wideTableFieldMapper.selectList(
                new LambdaQueryWrapper<WideTableField>()
                    .eq(WideTableField::getWideTableId, wideTableId)
                    .eq(WideTableField::getDeleted, false)
            );
            if (fields.isEmpty()) {
                throw new RuntimeException("宽表字段配置为空");
            }
            
            // 解析Excel文件
            List<Map<String, Object>> dataList = parseExcelFile(file, fields, taskStatus);
            
            if (taskStatus.getStatus() == ImportTaskStatus.TaskStatus.CANCELLED) {
                return;
            }
            
            // 批量导入到Elasticsearch
            importToElasticsearch(wideTable, fields, dataList, taskStatus);
            
            // 更新完成状态
            taskStatus.setStatus(ImportTaskStatus.TaskStatus.COMPLETED);
            taskStatus.setProgress(100);
            taskStatus.setEndTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            
        } catch (Exception e) {
            log.error("Excel导入失败: taskId={}, error={}", taskId, e.getMessage(), e);
            taskStatus.setStatus(ImportTaskStatus.TaskStatus.FAILED);
            taskStatus.setErrorMessage(e.getMessage());
            taskStatus.getErrorDetails().add("导入失败: " + e.getMessage());
            taskStatus.setEndTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        } finally {
            updateTaskStatus(taskId, taskStatus);
        }
    }
    
    private List<Map<String, Object>> parseExcelFile(MultipartFile file, List<WideTableField> fields, ImportTaskStatus taskStatus) throws IOException {
        List<Map<String, Object>> dataList = new ArrayList<>();
        AtomicLong totalRows = new AtomicLong(0);
        AtomicLong processedRows = new AtomicLong(0);
        AtomicLong successRows = new AtomicLong(0);
        AtomicLong errorRows = new AtomicLong(0);
        
        // 创建字段名映射
        Map<String, WideTableField> fieldMap = new HashMap<>();
        for (WideTableField field : fields) {
            fieldMap.put(field.getDisplayName(), field);
            fieldMap.put(field.getFieldName(), field);
        }
        
        try {
            EasyExcel.read(file.getInputStream())
                .head(LinkedHashMap.class)
                .registerReadListener(new PageReadListener<LinkedHashMap<Integer, String>>(dataRows -> {
                    totalRows.addAndGet(dataRows.size());
                    
                    for (LinkedHashMap<Integer, String> rowData : dataRows) {
                        if (taskStatus.getStatus() == ImportTaskStatus.TaskStatus.CANCELLED) {
                            return;
                        }
                        
                        try {
                            Map<String, Object> processedRow = processRowData(rowData, fieldMap);
                            if (processedRow != null) {
                                dataList.add(processedRow);
                                successRows.incrementAndGet();
                            }
                        } catch (Exception e) {
                            errorRows.incrementAndGet();
                            taskStatus.getErrorDetails().add("第" + (processedRows.get() + 1) + "行数据处理失败: " + e.getMessage());
                        }
                        
                        processedRows.incrementAndGet();
                        
                        // 更新进度(解析阶段占50%)
                        int progress = (int) ((processedRows.get() * 50) / Math.max(totalRows.get(), 1));
                        taskStatus.setProgress(progress);
                        taskStatus.setTotalRows(totalRows.get());
                        taskStatus.setProcessedRows(processedRows.get());
                        taskStatus.setSuccessRows(successRows.get());
                        taskStatus.setErrorRows(errorRows.get());
                        
                        // 每100行更新一次状态
                        if (processedRows.get() % 100 == 0) {
                            updateTaskStatus(taskStatus.getTaskId(), taskStatus);
                        }
                    }
                }, BATCH_SIZE))
                .sheet()
                .doRead();
        } catch (Exception e) {
            throw new IOException("Excel文件解析失败: " + e.getMessage(), e);
        }
        
        return dataList;
    }
    
    private Map<String, Object> processRowData(LinkedHashMap<Integer, String> rowData, Map<String, WideTableField> fieldMap) {
        Map<String, Object> processedRow = new HashMap<>();
        
        AtomicInteger columnIndex = new AtomicInteger(0);
        for (Map.Entry<Integer, String> entry : rowData.entrySet()) {
            String cellValue = entry.getValue();
            if (cellValue == null || cellValue.trim().isEmpty()) {
                columnIndex.incrementAndGet();
                continue;
            }
            
            // 根据列索引或值匹配字段
            WideTableField field = findFieldByIndex(fieldMap, columnIndex.get(), cellValue);
            if (field != null) {
                Object convertedValue = convertValue(cellValue, field);
                processedRow.put(field.getFieldName(), convertedValue);
            }
            
            columnIndex.incrementAndGet();
        }
        
        return processedRow.isEmpty() ? null : processedRow;
    }
    
    private WideTableField findFieldByIndex(Map<String, WideTableField> fieldMap, int columnIndex, String cellValue) {
        // 简化实现：按顺序匹配字段
        List<WideTableField> sortedFields = fieldMap.values().stream()
            .distinct()
            .sorted(Comparator.comparing(WideTableField::getSortOrder, Comparator.nullsLast(Integer::compareTo)))
            .toList();
            
        if (columnIndex < sortedFields.size()) {
            return sortedFields.get(columnIndex);
        }
        
        return null;
    }
    
    private Object convertValue(String cellValue, WideTableField field) {
        if (cellValue == null || cellValue.trim().isEmpty()) {
            return field.getNullable() ? null : field.getDefaultValue();
        }
        
        try {
            switch (field.getFieldType()) {
                case NUMBER:
                    return Double.parseDouble(cellValue.trim());
                case BOOLEAN:
                    return Boolean.parseBoolean(cellValue.trim()) || 
                           "1".equals(cellValue.trim()) || 
                           "是".equals(cellValue.trim()) || 
                           "true".equalsIgnoreCase(cellValue.trim());
                case DATE:
                    // 简化日期处理，实际应该支持多种日期格式
                    return cellValue.trim();
                case STRING:
                default:
                    return cellValue.trim();
            }
        } catch (Exception e) {
            log.warn("字段值转换失败: field={}, value={}, error={}", field.getFieldName(), cellValue, e.getMessage());
            return cellValue.trim();
        }
    }
    
    private void importToElasticsearch(WideTable wideTable, List<WideTableField> fields, 
                                     List<Map<String, Object>> dataList, ImportTaskStatus taskStatus) {
        if (dataList.isEmpty()) {
            return;
        }
        
        String indexName = wideTable.getEsIndexName();
        if (indexName == null || indexName.trim().isEmpty()) {
            indexName = "wide_table_" + wideTable.getId();
        }
        
        AtomicLong importedCount = new AtomicLong(0);
        
        // 分批导入
        for (int i = 0; i < dataList.size(); i += BATCH_SIZE) {
            if (taskStatus.getStatus() == ImportTaskStatus.TaskStatus.CANCELLED) {
                return;
            }
            
            int endIndex = Math.min(i + BATCH_SIZE, dataList.size());
            List<Map<String, Object>> batch = dataList.subList(i, endIndex);
            
            try {
                // 使用ElasticsearchService进行批量导入
                boolean success = elasticsearchService.bulkInsert(indexName, batch);
                if (success) {
                    importedCount.addAndGet(batch.size());
                } else {
                    taskStatus.getErrorDetails().add("批量导入失败: batch=" + i + "-" + endIndex);
                }
                
                // 更新进度(导入阶段占50%，从50%开始)
                int progress = 50 + (int) ((importedCount.get() * 50) / dataList.size());
                taskStatus.setProgress(progress);
                updateTaskStatus(taskStatus.getTaskId(), taskStatus);
                
            } catch (Exception e) {
                log.error("批量导入失败: batch={}-{}, error={}", i, endIndex, e.getMessage());
                taskStatus.getErrorDetails().add("批量导入失败: " + e.getMessage());
            }
        }
        
        // 更新宽表数据统计
        wideTable.setDataCount((long) importedCount.get());
        wideTable.setUpdateTime(LocalDateTime.now());
        wideTableMapper.updateById(wideTable);
    }
    
    private void updateTaskStatus(String taskId, ImportTaskStatus taskStatus) {
        taskStatusMap.put(taskId, taskStatus);
        redisTemplate.opsForValue().set(TASK_STATUS_KEY + taskId, taskStatus, 24, TimeUnit.HOURS);
    }
}